/******************************************************
 * @file camera_page.c
 * @author Destiny 
 * @brief 相机页面构造程序
 * @version 0.1
 * @date 2024-07-18
 *****************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>

/* Private Includes ----------------------------------------------------------*/
#include "config.h"
#include "render.h"
#include "file.h"
#include "page_manager.h"
#include "video_manager.h"

/* Private typedef -----------------------------------------------------------*/

/* Private Define ------------------------------------------------------------*/


#define VIDEO_DEVICE_NAME    "v4l2"    /* 设备名称 */

/* Private variables ---------------------------------------------------------*/

static T_VideoDevice g_tVideoDevice ;  /* Video设备描述结构体 */

/*菜单栏信息*/
static T_Layout g_atMenuIconsLayout[] = {
    //	{0, 0, 0, 0, "return.bmp"},
    {0, 0, 0, 0, "/opt/icon/Menu/return.bmp"},
    {0, 0, 0, 0, "/opt/icon/Menu/shot.bmp"},
    {0, 0, 0, 0, "/opt/icon/Menu/home.bmp"},
    {0, 0, 0, 0, NULL},
};

/*页面菜单栏布局信息*/
static T_PageLayout g_tCameraPageMenuIconsLayout = {
    .iMaxTotalBytes = 0,
    .atLayout = g_atMenuIconsLayout,
};

static T_PixelDatas g_tCameraPixelDatas;   //缩放后的摄像头数据
static int g_iStartX,g_iStartY;            //摄像头图像数据显示起点坐标（左上角）    
static int g_iPthreadStop;                 //为1时，采集摄像头数据                              
static int g_iTakePicture;                 //拍照
/* Private Function Prototypes -----------------------------------------------*/
/**
 * @brief 计算页面显示区域分布 
*/
static void CalcCameraPageFrameLayout(void)
{
    int iXres, iYres, iBpp;
    int iTopLeftX, iTopLeftY;
    int iBotRightX, iBotRightY;

    GetDispResolution(&iXres, &iYres, &iBpp);
    /*确定文件显示区域*/
    if (iXres < iYres)
    {

        iTopLeftX = 0;
        iBotRightX = iXres - 1;
        iTopLeftY = g_atMenuIconsLayout[0].iBotRightY + 1;
        iBotRightY = iYres - 1;
    }
    else
    {
        iTopLeftX = g_atMenuIconsLayout[0].iBotRightX + 1;
        iBotRightX = iXres - 1;
        iTopLeftY = 0;
        iBotRightY = iYres - 1;
    }

    /*确定文件显示区域大小，以及图标字节数*/
    g_tCameraPixelDatas.iBpp = iBpp;
    g_tCameraPixelDatas.iWidth        = iBotRightX  -  iTopLeftX;
    g_tCameraPixelDatas.iHeight       = iBotRightY  -  iTopLeftY;
    g_tCameraPixelDatas.iLineBytes    = g_tCameraPixelDatas.iWidth * iBpp/8;
    g_tCameraPixelDatas.iTotalBytes   = g_tCameraPixelDatas.iLineBytes * g_tCameraPixelDatas.iHeight;

    g_iStartX = iTopLeftX;
    g_iStartY = iTopLeftY;
}

/**
 * @brief  获得输入事件，返回值为被选择的图标索引，用于菜单栏
 * 
 * @param ptPageLayout 页面布局区域信息
 * @param ptInputEvent 输入事件信息
 * @return int 成功：被选择的图标索引;失败：-1
*/
static int CameraPageGetInputEvent(PT_PageLayout ptPageLayout, PT_InputEvent ptInputEvent)
{
    return GenericGetInputEvent(ptPageLayout, ptInputEvent);
}

/**
 * @brief 显示页面 
 * 
 * @param ptPageLayout 页面布局信息
*/
static void ShowCameraPage(PT_PageLayout ptPageLayout)
{
    PT_VideoMem ptPageVideoMem;
    int iError;
    int iNumMenu;
    (void)iError;
    /*申请获得缓冲区*/
    ptPageVideoMem = GetVideoMem(ID("camera"), 1);
    if (ptPageVideoMem == NULL)
    {
        DBG_PRINTF(DLOG_LVL_ERROR,DLOG_TAG,"can't get video mem for camera page!\n");
        return;
    }

    /*图标位置计算*/
    if(!ptPageLayout->iMaxTotalBytes)
    {
        iNumMenu = (sizeof(g_atMenuIconsLayout)/sizeof(T_Layout) - 1);
        CalculatePageMenusLayout(ptPageLayout,iNumMenu);
        CalcCameraPageFrameLayout();
    }
    /*分配摄像头数据内存*/
    g_tCameraPixelDatas.aucPixelDatas = malloc(g_tCameraPixelDatas.iTotalBytes);
    /*将数据写入缓冲区*/
    iError = GeneratePage(ptPageLayout, ptPageVideoMem);

    /*缓冲区数据写入显示设备显存*/
    FlushVideoMemToDev(ptPageVideoMem);
    /*释放缓冲区*/
    PutVideoMem(ptPageVideoMem);
}

/**
 * @brief 获取摄像头数据
 * 
 * @param arg 显示缓冲区
*/
static void *GetFrameFrmCamera(void *arg)
{
    int iError;
    PT_VideoOpr ptVideoOpr;
    T_VideoBuf tVideoBuf;
    PT_VideoMem ptVideoMem = *((PT_VideoMem *) arg);
    /* 得到Video设备操作函数结构体指针 */
    ptVideoOpr = GetVideoOpr(VIDEO_DEVICE_NAME);
    if(!ptVideoOpr)
    {
        DBG_PRINTF(DLOG_LVL_ERROR,DLOG_TAG,"GetVideoOpr error!\n");
        pthread_exit((void *)-1);
    }
    /* 初始化这个设备 */
    iError = ptVideoOpr->InitDevice(VIDEO_DEVICE_PATH,&g_tVideoDevice);
    if(iError < 0)
    {
        DBG_PRINTF(DLOG_LVL_ERROR,DLOG_TAG,"InitDevice error!\n");
        pthread_exit((void *)-1);
    }
    /* 开始视频采集 */
    iError =  ptVideoOpr->StartDevice(&g_tVideoDevice);
    if(iError < 0)
    {
        DBG_PRINTF(DLOG_LVL_ERROR,DLOG_TAG,"StartDevice error!\n");
        pthread_exit((void *)-1);
    }

    /* 如果开始采集 */
    while(g_iPthreadStop)
    {
        /* 读取一帧图像数据*/
        iError = ptVideoOpr->GetFrame(&g_tVideoDevice,&tVideoBuf);
        if(iError < 0)
        {
            DBG_PRINTF(DLOG_LVL_ERROR,DLOG_TAG,"GetFrame error!\n");
            pthread_exit((void *)-1);
        }
        /* “拍照” */
        if(g_iTakePicture)
        {
            if(SavePixelDataAsBmp(&tVideoBuf.tPixelDatas) < 0)
            {
                DBG_PRINTF(DLOG_LVL_ERROR,DLOG_TAG,"SavePictureAsBmp error!\n");
            }
            g_iTakePicture = 0;
        }
        /* 缩放合适大小 */
        PicZoom(&tVideoBuf.tPixelDatas,&g_tCameraPixelDatas);

        PicMerge(g_iStartX,g_iStartY,&g_tCameraPixelDatas,&ptVideoMem->tPixelDatas);
        iError = ptVideoOpr->PutFrame(&g_tVideoDevice,&tVideoBuf);
        if(iError < 0)
        {
            DBG_PRINTF(DLOG_LVL_ERROR,DLOG_TAG,"PutFrame error!\n");
            pthread_exit((void *)-1);
        }
    }
    ptVideoOpr->ExitDevice(&g_tVideoDevice);
    free(g_tCameraPixelDatas.aucPixelDatas);
    g_tCameraPixelDatas.aucPixelDatas = NULL;
    pthread_exit(NULL);
}

/**
 * @brief 相机运行逻辑
 * 
 * @param ptParentPageParams 父页面参数
*/
static void CameraPageRun(PT_PageParams ptParentPageParams)
{
    int iIndex;
    T_InputEvent tInputEvent;
    T_InputEvent tInputEventPrePress;

    int bIconPressed = 0;

    int iIndexPressed = -1;


    int iError;
    PT_VideoMem ptDevVideoMem;

    // T_PageParams tPageParams;
    // tPageParams.iPageID = ID("camera");


    /*得到显示设备显存地址*/
    ptDevVideoMem = GetDevVideoMem();

    /*时间时间初始化*/
    tInputEventPrePress.tTime.tv_sec = 0;
    tInputEventPrePress.tTime.tv_usec = 0;


    /*显示页面数据*/
    ShowCameraPage(&g_tCameraPageMenuIconsLayout);
     
    /*创建图像采集线程*/
    pthread_t tid;

    g_iPthreadStop = 1;
    g_iTakePicture = 0;
    iError = pthread_create(&tid, NULL, GetFrameFrmCamera, (void *)&ptDevVideoMem);
    if (iError != 0) {
        perror("Thread creation failed");
        return;
    }
     
    while (1)
    {  
        /*读取输入事件,获取按钮索引*/
        iIndex = CameraPageGetInputEvent(&g_tCameraPageMenuIconsLayout, &tInputEvent);
          
        /* 触点不在菜单图标上, 则判断是在哪一个"目录和文件"上 */
        if (iIndex == -1)
        {
            continue;
        }
        /*按键被松开*/
        if (tInputEvent.iPressure == 0)
        {
            /*如果没有图标被按下，不做处理*/
            if (!bIconPressed)
            {
                continue;
            }
            bIconPressed = 0;
            /*按下和松开的是同一个图标*/
            if (iIndexPressed == iIndex)
            {
                switch (iIndex)
                {
                    case 0: /* 返回按钮 */
                    {
                        InvertButton(&g_atMenuIconsLayout[iIndexPressed],ptDevVideoMem);
                        g_iPthreadStop = 0;

                        pthread_join(tid,NULL);

                        //pthread_cancel(&tid);
                        return;
                    }
                    case 1: /* 拍照按钮 */
                    {
                        InvertButton(&g_atMenuIconsLayout[iIndexPressed],ptDevVideoMem);
			
                        g_iTakePicture = 1;
                        break;
                    }
                    case 2:   /*home键*/
                    {     
                        g_iPthreadStop = 0;

                        pthread_join(tid,NULL);

                        //pthread_cancel(&tid);
                        return ;
                    }
                    default:
                    {
                        break;
                    }
                }
            }
        }
        else     /*按键被按下*/
        {
            if (iIndex == -1)   /*事件无效*/
            {
                continue;
            }
            if (!bIconPressed) /*没有文件被按下*/
            {
                bIconPressed = 1;
                iIndexPressed = iIndex;
                tInputEventPrePress = tInputEvent;
                InvertButton(&g_atMenuIconsLayout[iIndex],ptDevVideoMem);
            }
            if (iIndexPressed == 0) /* 长按"向上"按钮退出*/
            {
                if (TimeMSBetween(tInputEventPrePress.tTime, tInputEvent.tTime) > 2000)
                {
                    return;
                }
            }
        }
    }
}

/**
 * @brief 相机页面结构体
 * 
*/
static T_PageAction g_tCameraPageAction = {
    .name = "camera",
    .Run = CameraPageRun,
    .GetInputEvent = CameraPageGetInputEvent,
    //.Prepare       = CameraPagePrepare;
};

/* Public Function Prototypes ------------------------------------------------*/

/**
 * @brief 相机页面注册函数
 * 
 * @return int 成功：0;失败：其他
*/
int CameraPageInit(void)
{
    return RegisterPageAction(&g_tCameraPageAction);
}
